import random

from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from web import models
from utils.sms import send_sms_single
from django_redis import get_redis_connection
from utils.encrypt import md5
from web.forms.bootstrform import BootstrapForm


class ResigterModel(BootstrapForm, forms.ModelForm):
    # 重写models的phone设置电话合法性效验规则
    phone = forms.CharField(label='电话', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9]\d{9}$)', '手机格式错误')])
    # 重写models的pwd设置密文保护
    pwd = forms.CharField(label='密码',
                          min_length=8,
                          max_length=64,
                          error_messages={
                              'min_length': '密码长度不能小于8个字符',
                              'max_length': '密码长度不能大于64个字符'
                          },
                          widget=forms.PasswordInput())
    # 添加确认密码字段
    confirm_pwd = forms.CharField(label='确认密码',
                                  min_length=8,
                                  max_length=64,
                                  error_messages={
                                      'min_length': '重复密码长度不能小于8个字符',
                                      'max_length': '重复密码长度不能大于64个字符'
                                  },
                                  widget=forms.PasswordInput())
    # 添加验证码字段
    code = forms.CharField(label='验证码',
                           widget=forms.TextInput())

    class Meta:
        model = models.WebUser
        fields = ['name', 'email', 'pwd', 'confirm_pwd', 'phone', 'code']  # 指定字段排列顺序

    def clean_name(self):
        name = self.cleaned_data['name']
        exists = models.WebUser.objects.filter(name=name).exists()
        if exists:
            raise ValidationError('用户名已存在！')
        return name

    def clean_email(self):
        email = self.cleaned_data['email']
        exists = models.WebUser.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在！')
        return email

    def clean_pwd(self):
        pwd = self.cleaned_data['pwd']
        return md5(pwd)

    def clean_confirm_pwd(self):
        pwd = self.cleaned_data.get('pwd')  # cleaned_data仅保存校验后的数据，注意校验规则顺序
        confirm_pwd = md5(self.cleaned_data['confirm_pwd'])
        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')
        return confirm_pwd

    def clean_phone(self):
        phone = self.cleaned_data['phone']
        exists = models.WebUser.objects.filter(phone=phone).exists()
        if exists:
            raise ValidationError('手机号已经注册')
        return phone

    def clean_code(self):
        code = self.cleaned_data['code']
        phone = self.cleaned_data.get('phone')
        conn = get_redis_connection()
        redis_code = conn.get(phone)
        if not redis_code:
            raise ValidationError('验证码生效或未发送，请重新发送！')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码不正确！请重新输入！')


class SendSmsForm(forms.Form):  # 和数据库没关系，仅用于表单验证，使用Form
    phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9]\d{9}$)', '手机格式错误！')])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_phone(self):
        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        temp_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not temp_id:
            raise ValidationError('模板错误！')
        # 判断手机号是否存在
        phone = self.cleaned_data['phone']
        exists = models.WebUser.objects.filter(phone=phone).exists()
        if exists and tpl == 'register':
            raise ValidationError('手机号已存在！')
        if not exists and tpl == 'login':
            raise ValidationError('手机号不存在！')
        # 发短信和写入redis
        code = random.randrange(1000, 9999)
        result = send_sms_single(phone, temp_id, [code, ])
        if result['result']:
            raise ValidationError(f'短信发送失败，{result["errmsg"]}')
        conn = get_redis_connection()
        conn.set(phone, code, ex=60)

        return phone


class LoginSmsForm(BootstrapForm, forms.Form):
    phone = forms.CharField(label='电话', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9]\d{9}$)', '手机格式错误')])
    code = forms.CharField(label='验证码',
                           widget=forms.TextInput())

    def clean_phone(self):
        phone = self.cleaned_data['phone']
        user_object = models.WebUser.objects.filter(phone=phone).first()  # 获取用户对象
        if not user_object:
            raise ValidationError('手机号不存在!')
        return user_object

    def clean_code(self):
        code = self.cleaned_data['code']
        user_object = self.cleaned_data.get('phone')
        if not user_object:
            return code
        conn = get_redis_connection()
        redis_code = conn.get(user_object.phone)
        if not redis_code:
            raise ValidationError('验证码生效或未发送，请重新发送')
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新填写')
        return code


class LoginForm(BootstrapForm, forms.Form):
    name = forms.CharField(label='邮箱或手机号')
    pwd = forms.CharField(label='密码',
                          min_length=8,
                          max_length=64,
                          error_messages={
                              'min_length': '重复密码长度不能小于8个字符',
                              'max_length': '重复密码长度不能大于64个字符'
                          }, widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='图片验证码')

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_code(self):
        '''判断图片验证码是否正确'''
        code = self.cleaned_data['code']
        session_code = self.request.session.get('image_code')
        if not session_code:
            raise ValidationError('验证码已过期，请重新获取！')
        if code.strip().upper() != session_code.strip().upper():
            raise ValidationError('验证码不正确！')
        return code

    def clean_pwd(self):
        pwd=self.cleaned_data['pwd']
        return md5(pwd)
